Option Explicit

' 用指定分隔符连接 Collection 中的每个元素
' 如果某个元素是一个 Object 类型的对象，无法生成字符串，只会为这个对象写入一个空格
' @param c Collection
' @param delimiter 分隔符
' @return String
Public Function joinElem(ByRef c As Collection, ByVal delimiter As String) As String
    Dim counts As Integer
    Dim i As Integer
    counts = c.count

    If counts = 0 Then
        joinElem = ""
        Exit Function
    End If

    For i = 1 To counts - 1
        If IsObject(c(i)) Then
            joinElem = joinElem & " " & delimiter
        Else
            joinElem = joinElem & c(i) & delimiter
        End If
    Next

    If IsObject(c(counts)) Then
        joinElem = joinElem & " "
    Else
        joinElem = joinElem & c(counts)
    End If
End Function

' 在 Collection 中检索指定字符串的 index
' @param src Collection
' @param v 待检索的数据
' @return Integer
'         如果不存在，则返回 -1
Public Function indexOf(ByRef src As Collection, ByRef v As Variant) As Integer
    indexOf = -1

    ' 1. 如果 src 是空，或者没有元素，则直接返回 -1
    If src Is Nothing Then
        Exit Function
    End If
    If src.Count = 0 Then
        Exit Function
    End If

    ' 2. 检查 v 的类型，按照对象类型、基础数据类型分别处理
    Dim i As Integer
    Dim e As Variant
    i = 1
    If IsObject(v) Then
        ' 按照对象类型检索
        For Each e In src
            ' 只在元素是对象类型时，才进行处理
            If IsObject(e) Then
                If e Is v Then
                    indexOf = i
                    Exit Function
                End If
            End If
            i = i + 1
        Next
    Else
        ' 按照基础数据类型检索
        For Each e In src
            ' 只在元素是基础数据类型时，才进行处理
            If Not IsObject(e) Then
                If e = v Then
                    indexOf = i
                    Exit Function
                End If
            End If
            i = i + 1
        Next
    End If

End Function

' 合并两个集合，将 src 合并到 desc
' 该方法只负责合并基础类型数据
' 如果 src 中存在和 desc 相同的数据，则忽略这个数据。src 中的重复数据也只会保存一次
' @param desc 保存数据的对象
' @param src 数据源
Public Sub mergePrimitiveVal(ByRef desc As Collection, ByRef src As Collection)
    Dim descTemp As Variant
    Dim srcTemp As Variant
    Dim tempColl As Collection
    Set tempColl = New Collection

    ' 从 src 中抽取不存在于 desc 中的数据
    For Each srcTemp In src

        ' 1. 先在 tempColl 中检查，以避免 src 中的重复数据
        For Each descTemp In tempColl
            If srcTemp = descTemp Then
                ' 如果相同，则 continue
                GoTo loop1
            End If
        Next

        ' 2. 再在 desc 中检查
        For Each descTemp In desc
            If srcTemp = descTemp Then
                ' 如果相同，则 continue
                GoTo loop1
            End If
        Next

        tempColl.Add srcTemp
loop1:
    Next

    If tempColl.count > 0 Then
        Dim temp As Variant
        For Each temp In tempColl
            desc.Add temp
        Next
    End If

    Set tempColl = Nothing
End Sub

' 合并两个集合，将 src 合并到 desc
' 该方法只负责合并对象类型数据
' 如果 src 中存在和 desc 相同的数据，则忽略这个数据。src 中的重复数据也只会保存一次
' @param desc 保存数据的对象
' @param src 数据源
Public Sub mergeObjVal(ByRef desc As Collection, ByRef src As Collection)
    Dim descTemp As Variant
    Dim srcTemp As Variant
    Dim tempColl As Collection
    Set tempColl = New Collection

    ' 从 src 中抽取不存在于 desc 中的数据
    For Each srcTemp In src

        ' 1. 先在 tempColl 中检查，以避免 src 中的重复数据
        For Each descTemp In tempColl
            If srcTemp Is descTemp Then
                ' 如果相同，则 continue
                GoTo loop1
            End If
        Next

        ' 2. 再在 desc 中检查
        For Each descTemp In desc
            If srcTemp Is descTemp Then
                ' 如果相同，则 continue
                GoTo loop1
            End If
        Next

        tempColl.Add srcTemp
loop1:
    Next

    If tempColl.count > 0 Then
        Dim temp As Variant
        For Each temp In tempColl
            desc.Add temp
        Next
    End If

    Set tempColl = Nothing
End Sub

' 将 src 集合中的元素全部添加到 desc
' @param desc As Collection
' @param src As Collection
Public Sub addAllCollection(ByRef desc As Collection, ByRef src As Collection)
    Dim e As Variant
    For Each e In src
        desc.Add e
    Next
End Sub

' 如果数组中不存在指定元素，则向数组中插入该元素
' 只处理基础数据类型
' @param desc 保存数据的对象
' @param elem 需要保存的数据
Public Sub addIfNecessaryForPrimitive(ByRef desc As Collection, ByRef elem As Variant)
    If desc Is Nothing Then
        Exit Sub
    End If

    Dim temp As Variant
    For Each temp In desc
        If temp = elem Then
            Exit Sub
        End If
    Next

    desc.Add elem
End Sub

' 如果数组中不存在指定元素，则向数组中插入该元素
' 只处理对象数据类型
' @param desc 保存数据的对象
' @param elem 需要保存的数据
Public Sub addIfNecessaryForObj(ByRef desc As Collection, ByRef elem As Variant)
    If desc Is Nothing Then
        Exit Sub
    End If

    Dim temp As Variant
    For Each temp In desc
        If temp Is elem Then
            Exit Sub
        End If
    Next

    desc.Add elem
End Sub

' 清空指定 Collection 对象中的所有数据
' @param c 需要清空数据的 Collection 对象
Public Sub removeAllCollection(ByRef c As Collection)
    Dim i As Integer
    i = c.Count
    If i > 0 Then
        Do Until i = 0
            c.Remove (i)
            i = i - 1
        Loop
    End If
End Sub

' 将指定 Collection 对象中的所有数据保存到一个数组中
' @param c Collection 对象
' @return 保存了 collection 对象所有数据的数组
Public Function toVariantArray(ByRef c As Collection) As Variant()
    Dim result() As Variant

    If c.count = 0 Then
        ReDim result(0 To 0)
    Else
        ReDim result(0 To c.count - 1)

        Dim i As Integer
        For i = 0 To c.count - 1
On Error GoTo catch
            result(i) = c.Item(i + 1)
            GoTo continue
catch:
            Err.Clear
            Set result(i) = c.Item(i + 1)
            Resume continue
continue:
        Next
    End If

    toVariantArray = result
End Function

' 克隆一个 Collection 对象
' @param src 需要克隆的 Collection 对象
' @return 克隆后的 Collection
'         基础类型数据将会进行数据复制
'         对象数据类型只能复制引用
Public Function cloneCollection(ByRef src As Collection) As Collection
    ' 1. 创建一个新的 collection，用来拷贝数据
    Dim result As Collection
    Set result = New Collection

    ' 2. 拷贝数据
    UtilsCollection.addAllCollection result, src

    Set cloneCollection = result
End Function
